package cn.mehoyo.certificateGeneration.common;

import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 缓存Map，支持序列化到本地文件
 * @author llh
 */
public class LocalCacheMap {

    /** 静态共享清理线程 */
    private static final ScheduledExecutorService CLEANER =
            Executors.newSingleThreadScheduledExecutor(r -> {
                Thread t = new Thread(r, "cache-cleaner");
                t.setDaemon(true);
                return t;
            });

    /**
     * 是否已经启动清理线程
     */
    private static final AtomicBoolean CLEANER_STARTED = new AtomicBoolean(false);

    /** 全部实例列表，用于清理线程统一扫描 */
    private static final List<LocalCacheMap> INSTANCES = new CopyOnWriteArrayList<>();

    /** 实例内部缓存 */
    private final Map<String, Object> MAP = new ConcurrentHashMap<>();
    private final ConcurrentSkipListMap<Long, String> EXPIRE_MAP = new ConcurrentSkipListMap<>();
    private final Map<String, Long> REVERSE_MAP = new ConcurrentHashMap<>();

    /** 每个实例是否初始化 */
    private final AtomicBoolean initialized = new AtomicBoolean(false);

    /** 本地缓存文件路径 */
    private static final String CACHE_DIR_PATH = "cache";
    private static final String CACHE_FILE_PATH = CACHE_DIR_PATH + "/cache_map.ser";

    /** 私有构造，禁止直接 new */
    private LocalCacheMap() { }

    /** 初始化并返回实例，第一次初始化启动清理线程 */
    public static LocalCacheMap initialize() {
        LocalCacheMap instance = new LocalCacheMap();
        instance.start();
        return instance;
    }

    /** 启动实例，注册到全局实例列表 */
    private void start() {
        if (!initialized.compareAndSet(false, true)) {
            return;
        }
        INSTANCES.add(this);

        // 全局只启动一次清理线程
        if (CLEANER_STARTED.compareAndSet(false, true)) {
            CLEANER.scheduleAtFixedRate(LocalCacheMap::cleanAll, 1, 1, TimeUnit.SECONDS);
        }

        // 加载本地缓存
        loadFromFile();
    }

    /** 清理所有实例的过期缓存 */
    private static void cleanAll() {
        long now = System.currentTimeMillis();
        for (LocalCacheMap cache : INSTANCES) {
            ConcurrentNavigableMap<Long, String> expired = cache.EXPIRE_MAP.headMap(now, true);
            if (!expired.isEmpty()) {
                List<String> expiredKeys = new ArrayList<>(expired.values());
                expiredKeys.forEach(k -> {
                    cache.MAP.remove(k);
                    cache.REVERSE_MAP.remove(k);
                });
                expired.clear();
            }
        }
    }

    /** 将缓存数据保存到本地文件 */
    private void saveToFile() {
        // 创建目录（如果目录不存在）
        Path cacheDir = Paths.get(CACHE_DIR_PATH);
        if (Files.notExists(cacheDir)) {
            try {
                Files.createDirectories(cacheDir);  // 创建目录
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("无法创建缓存目录: " + CACHE_DIR_PATH);
            }
        }

        // 保存文件
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(CACHE_FILE_PATH))) {
            out.writeObject(MAP);
            out.writeObject(EXPIRE_MAP);
            out.writeObject(REVERSE_MAP);
            System.out.println("缓存已保存到本地文件: " + CACHE_FILE_PATH);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /** 从本地文件加载缓存数据 */
    private void loadFromFile() {
        // 尝试加载本地文件
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(CACHE_FILE_PATH))) {
            // 清空现有缓存
            MAP.clear();
            EXPIRE_MAP.clear();
            REVERSE_MAP.clear();

            // 从文件中读取数据
            Map<String, Object> loadedMap = (Map<String, Object>) in.readObject();
            ConcurrentSkipListMap<Long, String> loadedExpireMap = (ConcurrentSkipListMap<Long, String>) in.readObject();
            Map<String, Long> loadedReverseMap = (Map<String, Long>) in.readObject();

            // 加载到内存
            MAP.putAll(loadedMap);
            EXPIRE_MAP.putAll(loadedExpireMap);
            REVERSE_MAP.putAll(loadedReverseMap);

            System.out.println("缓存从本地文件加载完成: " + CACHE_FILE_PATH);
        } catch (IOException | ClassNotFoundException e) {
            // 文件不存在或文件无法读取时，不处理
            System.out.println("本地缓存文件不存在或读取失败，使用空缓存");
        }
    }

    public void put(String key, Object value, TimeUnit timeUnit, long time) {
        MAP.put(key, value);
        long expireTime = System.currentTimeMillis() + timeUnit.toMillis(time);
        EXPIRE_MAP.put(expireTime, key);
        REVERSE_MAP.put(key, expireTime);

        // 每次 put 都保存到本地
        saveToFile();
    }

    public void put(String key, Object value) {
        MAP.put(key, value);

        // 每次 put 都保存到本地
        saveToFile();
    }

    public Object get(String key) {
        return MAP.get(key);
    }

    public void remove(String key) {
        MAP.remove(key);
        Long expireKey = REVERSE_MAP.remove(key);
        if (expireKey != null) {
            EXPIRE_MAP.remove(expireKey);
        }

        // 每次 remove 都保存到本地
        saveToFile();
    }
}
